#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#include <arpa/inet.h>

#include "dns_packet_parsing.h"
#include "dns_util.h"

/*
 * Functions
 */

/* Print the given error message or the default usage line */
void usage(const char * custom_message, const char * exec_name) {
  if (custom_message != NULL)
    fprintf(stderr, "%s\n", custom_message);
  fprintf(stderr, "Usage: %s -s server_ip [-p server_port] domain_name\n", exec_name);
  exit(EXIT_FAILURE);
}

/*
 * Main
 */
int main(int argc, char ** argv) {

  /* Arguments */
  char server_ip[IPV4_STR_LENGTH];
  int server_port = DNS_DEFAULT_PORT;
  char domain_name[DOMAIN_STR_LENGTH];

  /* Read arguments */
  if (argc != 4 && argc != 6)
    usage("Wrong number of arguments", argv[0]);
  if (strcmp(argv[1], "-s") == 0)
    strcpy(server_ip, argv[2]);
  else
    usage("Missing parameter '-s'", argv[0]);
  if (strcmp(argv[3], "-p") == 0) {
    server_port = atoi(argv[4]);
    strcpy(domain_name, argv[5]);
  } else if (argc == 4)
    strcpy(domain_name, argv[3]);
  else
    usage("Wrong option", argv[0]);

  /* --- */

  SOCKET client_socket = INVALID_SOCKET;
  SOCKADDR_IN server_addr;
  socklen_t server_addr_len;

  /* Create socket  */
  if ((client_socket = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
    exit_syserr("socket()", &client_socket, NULL);

  /* Init server address */
  server_addr_len = sizeof(server_addr);
  memset(&server_addr, 0, server_addr_len);
  server_addr.sin_family = AF_INET;
  server_addr.sin_port = htons(server_port);
  server_addr.sin_addr.s_addr = inet_addr(server_ip);

  /* Build question */
  char buffer[BUF_SIZE] = { 0 };
  int msg_length = build_dns_request(buffer, domain_name);

  /* Send question */
  if ((sendto(client_socket, buffer, msg_length, 0, (SOCKADDR *) &server_addr, server_addr_len)) < 0)
    exit_syserr("sendto()", &client_socket, NULL);

  /* Wait for answer */
  if (recvfrom(client_socket, buffer, BUF_SIZE, 0, (SOCKADDR *) &server_addr, &server_addr_len) < 0)
    exit_syserr("recvfrom()", &client_socket, NULL);

  /* Check name error */
  if (buffer[3] & 3) {
    printf("No such name\n");
    close_socket(&client_socket);
    exit(EXIT_FAILURE);
  }

  /* Print result IP */
  unsigned char ipv4_addr[4];
  ip_from_answer(buffer, ipv4_addr);
  printf("%d.%d.%d.%d\n", ipv4_addr[0], ipv4_addr[1], ipv4_addr[2], ipv4_addr[3]);

  /* --- */

  close_socket(&client_socket);

  return EXIT_SUCCESS;
}
